<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        #number {
            width: 300px;
            line-height: 30px;
            padding: 0 10px;
            font-size: 16px;
        }

        span {
            margin: 20px;
            display: inline-block;
            color: brown;
        }

        #btn {
            height: 30px;
            font-size: 16px;
        }
    </style>
</head>

<body>
    请输入数字（支持正负数字）：<input id="number" type="text">
    <input id="btn" type="button" value="点击转换" onclick="numTranslateCh()" />
    <br>
    转换中文：<span id="result"></span>
    <br>
    转换人民币（小数点只取后两位）：<span id="money"></span>
    <br>
    转换中文（最大单位亿）：<span id="maxUnit"></span>
    <br>
    转换人民币（最大单位亿）：<span id="maxUnitMoney"></span>

    <script>
        
        //数字转变中文
        function numTranslateCh() {
            let numVal = document.getElementById('number').value;//获取数字，
            let numCh = numberTransformCh(numVal);
            document.getElementById("result").innerHTML = numCh || '';

            let money = numberTransformCh(numVal, true);
            document.getElementById("money").innerHTML = money || '';

            let maxUnit = numberTransformCh(numVal, false, '亿');
            document.getElementById("maxUnit").innerHTML = maxUnit || '';

            let maxUnitMoney = numberTransformCh(numVal, true, '亿');
            document.getElementById("maxUnitMoney").innerHTML = maxUnitMoney || '';
        }

        function numberTransformCh(num, money, unit) {
            let number = num || '';
            let isMoney = money || false;
            let maxUnit = unit || '';

            let result = '';
            let dotNumPrefix = ''; //小数点之前的数
            let dotNumSuffix = ''; //小数点之后的数
            // 数字对应中文
            let zhArr = !isMoney ? ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九'] : ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖']; 
            // 单位转变规律，中国为中数体系单位，每到千，换个单位，也就是到万进制一个单位，个位空
            let baseArr = !isMoney ? ['', '十', '百', '千'] : ['', '拾', '佰', '仟']; 
            // 单位递增规律，每隔千一进制，第一个为个位（个十百千），空
            let unitArr = ['', '万', '亿', '兆', '京', '垓', '秭', '穰', '沟', '涧', '正', '载', '极', '恒河沙', '阿僧祗', '那由他'];
            let maxUnitStatus = false;//判断单位是否匹配正确
            let numIsSign = false; //判断数字里面是否包含正负号。
            let numSign = ''; //保存正负号的符号。


            let numString = String(number).trim(); //数字转换为字符串
            
            if (!number) {
                alert("不能为空")
                return;
            }
            if (!/^[+-]?\d+(\.\d+)?$/.test(number)) {
                alert("请输入合法数字")
                return;
            }

            //判断数字是否带有正负号。
            if(numString.includes('+') || numString.includes('-')){
                numIsSign = true;
                numSign = numString.slice(0,1);
                numString = numString.slice(1);
            }

            let maxLength = unitArr.length * baseArr.length;
            let numLength = numString.includes('.') ? numString.split('.')[0].length : numString.length;
            if (numLength > maxLength) {
                alert("目前支持" + maxLength + "位以内数字")
                return;
            }
            

            if (maxUnit) {
                //判断所有单位是否存在，个十百千万亿.....
                if (baseArr.includes(maxUnit) || unitArr.includes(maxUnit)) {
                    //判断最小单位，最小到万
                    if (baseArr.includes(maxUnit) || unitArr.indexOf(maxUnit) < 1) {
                        console.error("参数错误：" + maxUnit + "，单位最小仅支持万，注意单位精度！！！");
                    } else {
                        maxUnitStatus = true; //单位正确，规则匹配true，下面判断用
                    }
                } else {
                    console.error("参数错误：" + maxUnit + "，单位不存在，注意支持单位精度！！！");
                }
            }


            //判断是否有小数点
            if (numString.includes('.')) {
                dotNumPrefix = numString.split('.')[0];
                dotNumSuffix = numString.split('.')[1];
            } else {
                dotNumPrefix = numString;
            }
            console.log("小数点前数字：" + dotNumPrefix);
            console.log("小数点后数字：" + dotNumSuffix);

            let numPrefixSplit = [];

            //数字从后向前每四位一拆分  
            let step = 4;
            for (let i = dotNumPrefix.length; i > 0; i = i - step) {
                let arr = '';
                if (i - step >= 0) {
                    arr = dotNumPrefix.slice(i - step, i);
                } else {
                    arr = dotNumPrefix.slice(0, i);
                }
                numPrefixSplit.unshift(arr);
            }
            console.log("数字每四位拆分为数组");
            console.log(numPrefixSplit)

            let resultArr = [];
            numPrefixSplit = numPrefixSplit.reverse();
            //按照拆分的四位数进行倒序转换，为了索引和上面的unitArr单位索引相对应
            for (let index = 0; index < numPrefixSplit.length; index++) {
                const item = numPrefixSplit[index];
                let elResult = item.split('').reverse().map((el, i) => {
                    /**
                     * 索引为0的即个位数，直接转换对应汉字，或者自身值就是0，也不拼接单位，直接转换汉字零（因为没有零十，零百，零千）
                     * 其他，后面拼接单位（个十百千）
                     * */
                    el = (i === 0 || Number(el) === 0) ? zhArr[Number(el)] : zhArr[Number(el)] + baseArr[i];
                    // console.log(el);
                    return el;
                }).reverse().join(''); // 倒叙回来数组，拼接成字符串

                /**
                * 如果有最大单位，且存在，那就判断要追加的单位是否是最大单位，如果是，就要对最大单位处理，同时跳出循环。
                */
                if (maxUnitStatus && unitArr[index] === maxUnit) {
                    // 删掉最大单位后面的数，后面已经排序完毕
                    let num = numPrefixSplit.slice(index).reverse().join('');
                    let arr = dealMaxunitResult(num, resultArr, maxUnit, zhArr, isMoney, numPrefixSplit.slice(0, index).reverse());
                    //这里同样要判断零条件，因为这里是最大单位后面的部分，不判断可能存在多个零情况，开头零不判断，有xxx零xxx
                    let resultArrJoin = resultArr.reverse().join('');
                    // 如果有多位相邻的零，只写一个零即可
                    resultArrJoin = resultArrJoin.replace(/零+/g, '零');
                    //这里零判断同上
                    if (resultArrJoin !== '零') {
                        // 如果以零结尾，可省略
                        resultArrJoin = resultArrJoin.replace(/零$/g, '');
                    }
                    resultArr = [resultArrJoin];
                    resultArr.push(arr)
                    break;
                }

                
                // 如果有多位相邻的零，只写一个零即可
                elResult = elResult.replace(/零+/g, '零');
                /**
                 * 先判断这个四位数是不是本身不是零，如果是零，零匹配成空格了
                 * 不等于零要加四位数间隔的单位（万，亿.....）
                 * */
                if (elResult !== '零') {
                    // elResult = elResult.replace(/^零/, ''); // 如果以零开头，可省略，这里是内项，不要判断此条件，有可能会有xxx零x的情况，最后结果判断即可。
                    // 如果以零结尾，可省略
                    elResult = elResult.replace(/零$/g, '');
                    //单位追加同上
                    elResult = elResult + unitArr[index]
                }
                // 如果以一十开头，可以改为十，人民币同理
                elResult = !isMoney ? elResult.replace(/^一十/g, '十') : elResult.replace(/^壹拾/g, '拾');

                resultArr.push(elResult)

            }

            //最终结果数组倒转即正确顺序，转为字符串。
            result = resultArr.reverse().join('');
            if (!maxUnitStatus) {
                // 如果有多位相邻的零，只写一个零即可
                result = result.replace(/零+/g, '零');
                //这里零判断同上
                if (result !== '零') {
                    // 如果以零开头，可省略
                    result = result.replace(/^零/g, '');
                    // 如果以零结尾，可省略
                    result = result.replace(/零$/g, '');
                }
            } else {
                // 如果前后有多位相邻的零，只写一个零即可，除了前后端的多个零可以合并，其他不行，中间的小数合并了就少了。
                result = result.replace(/^零+/g, '零');
                result = result.replace(/零+$/g, '零');
                //零特殊判断。
                if(result != '零'){
                    // 前面零省略，后面零结尾省略
                    result = result.replace(/^零/g, '');
                    result = result.replace(/零$/g, '');
                }
               
            }
            // 如果以一十开头，可以改为十，先去零，后判断一十
            result = !isMoney ? result.replace(/^一十/g, '十') : result.replace(/^壹拾/g, '拾');

            //以上小数点前面的处理完毕，小数点后就对应转中文即可
            let dotSuffixResult = '';
            if (dotNumSuffix.length > 0 ) {
                dotSuffixResult = !isMoney ? '点' : '';
                let dotNumSuffixArr = dotNumSuffix.split('')
                // 非人民币金额，直接循环转对应中文
                if (!isMoney) {
                    //判断小数点后面的值是否全是零，只有不是零的才处理,全为零则置空，去除上面的赋值的点，防止出bug
                    let noBothLing = dotNumSuffixArr.some(item => item != '0')
                    if(noBothLing) {
                        dotNumSuffixArr.forEach(item => {
                            dotSuffixResult = dotSuffixResult + zhArr[Number(item)]
                        })
                    }else {
                        dotSuffixResult = ''
                    }
                    
                } else {
                    let dotSuffixMoneyUnit = ['角', '分']
                    //人民币金额只要前两位
                    for (let i = 0; i < 2; i++) {
                        dotSuffixResult = dotSuffixResult + (zhArr[dotNumSuffixArr[i]] || '') + (zhArr[dotNumSuffixArr[i]] ? dotSuffixMoneyUnit[i] : '');
                    }
                }

            }
            // 小数点末尾后的零，可省略，没意义
            dotSuffixResult = dotSuffixResult.replace(/零+$/g, '');

            //判断数字是否带正负号，+ 默认去除正字。零也去除所有正负号，零就是零
            let numSignCh = '';
            if(numIsSign) {
                numSignCh = numSign === '-' && result != '零' ? '负' : '';
            }

            result = !isMoney ? result + dotSuffixResult : result + '元' + dotSuffixResult;
            result = numSignCh + result;

            console.log("----------");
            console.log(resultArr);
            console.log(result);
            return result;

            /**
             * 
             * 处理最大单位的数据
             * 
             * */
            function dealMaxunitResult(num, elResult, maxUnit, zhArr, isMoney, numLast) {
                num = num.replace(/^0+/g,'')
                if(num == 0){
                    return;
                }
                // 根据单位自动计算此单位后面有几个零。万就是四个零，亿八个零.....
                let stepCount = unitArr.indexOf(maxUnit) * baseArr.length;
                // 计算最大单位除数，比如万就是10000......
                // let divisor = Math.pow(10, stepCount);

                let intNum = '';//整除的整数部分
                let dotNum = '';//整除的剩余部分，余数，也就是小数
                let finalUnit = '';//单位拼接，需要多少个maxUnit

                let maxNumArr = [];
                //数字从后向前每stepCount位一拆分，maxUnit都是整数，maxUnit单位对应几个零，小数点左移几位
                for (let i = num.length; i > 0; i = i - stepCount) {
                    let item = ''
                    if (i - stepCount >= 0) {
                        item = num.slice(i - stepCount, i);
                    } else {
                        item = num.slice(0, i);
                    }
                    maxNumArr.unshift(item);
                }
                //以上得到根据最大单位拆分得到的数组，除了第一个项目代表整数部分，后面被整除的都是小数，所以整数重新获取，小数循环拼接

                //循环拿到的拆分数组，有几次循环代表有几个maxUnit单位
                maxNumArr.forEach((item, index) => {
                    finalUnit = finalUnit + maxUnit;
                    if (index == 0) {
                        intNum = item;
                    } else {
                        dotNum = dotNum + item;
                    }
                })

                console.log("intNum:" + intNum);
                console.log("dotNum:" + dotNum);
                console.log("finalUnit:" + finalUnit);


                let intNumCh = numberTransformCh(intNum, isMoney);
                //因为人民币结果会自动返回元，所以这里会返回一个汉字元，这里多余，去掉。
                if(isMoney){
                    intNumCh = String(intNumCh).replace(/元/g,'');
                }
                let dotNumCh = '';
                dotNum.split('').forEach(item => {
                    dotNumCh = dotNumCh + zhArr[Number(item)]
                })
                // 小数点末尾后的零，可省略，没意义
                dotNumCh = dotNumCh.replace(/零+$/g, '');


                console.log("intNumCh:" + intNumCh);
                console.log("dotNumCh:" + dotNumCh);
                console.log("finalUnit:" + finalUnit);

                /***
                 * 拼接最终单位，整数部分加点加小数部分再加最终单位
                 * 
                 * 点根据数组长度判断，只有大于1才代表有小数部分，加点，并且小数部分不能都是0，如果都是0点可省略
                 */

                let maxUnitResult = intNumCh + (maxNumArr.length > 1 && dotNum != 0 ? '点' : '') + dotNumCh + finalUnit;
                console.log(maxUnitResult);
                return [maxUnitResult]
            }

        }


    </script>
</body>

</html>